/*
* $Id: timer_fn.c,v 1.28 2008/02/21 08:01:27 chunchia Exp $
*/
/*******************************************************************************

       UBEC (Uniband Electronic Corp.)

       Project: U-NET01, Ubiquitous network platform

       File: func.c

       Version: 0.3.0

       Usage: oter function: Led, Timer...

       Platform: U-NET01 DK with Keil 8051 C compiler

       Reference:

               Silicon Laboratories: C8051F124, C8051F340

               UBEC: UZ2400, UZ2410

       Note : LED 4~7 Only for U-zig interface

               Copyright (C) 2007 Uniband Electronic Corporation, All rights reserved

********************************************************************************/
#if defined(__K0__)
#pragma section @@DATA @@TIMER
//#pragma inline  // enable memcpy() and memset() with direct inline expansion instead of function call
#endif // #if __K0__

#include "unet.h"

volatile UINT32 tick_count;		/* 1 millisecond system timer tick counter */
volatile BOOL timer_1ms_flag;

#if SEND_MSG_TIME_STAMP
volatile UINT8 MsgLineCnt;
#endif // #if SEND_MSG_TIME_STAMP

/*******************************************************************************

	Timer Function

********************************************************************************/
static void set_expire_time(TIMER *tm)
{
	UINT32 tick = tick_count;

	TRACE_printf(("set_expire_time(%p): %08lX + %08lX", tm, tick, tm->period_count));

	tm->expire_time = tick + tm->period_count;
	tm->overflow = (tm->expire_time < tick) ? 1 : 0;
	tm->expired = 0;
}

/*******************************************************************************
********************************************************************************/
TIMER *setup_timer(UINT32 count, UINT8 close_timer_flag, void (*fn)(), void *fn_param)
{
	if(insert_node((void *)&UnetSys.TimerTail, sizeof(TIMER)) == NULL) {
		TRACE_puts("setup_timer: insert_node() FAILURE");
		return NULL;
	}

	UnetSys.TimerTail->period_count = count;
	set_expire_time(UnetSys.TimerTail);

	UnetSys.TimerTail->close_timer_flag = close_timer_flag;
	UnetSys.TimerTail->fn = fn;
	UnetSys.TimerTail->fn_param = fn_param;
	UnetSys.TimerTail->timer_fn_busy = 0;

	return(UnetSys.TimerTail);
}

/*******************************************************************************
********************************************************************************/
UINT8 is_timer_expired(TIMER *target_tm)
{
	TIMER *tm;

    #if 1
	if(IntStatus.Rx) {	// Received a frame
		unet_msg_dispatch();
	}
    #endif

	if(timer_1ms_flag) {
		update_timer_chain();
	}

	if((tm = UnetSys.TimerTail) != NULL) {
	    do {
		if((tm = tm->Next) == target_tm)
			return(tm->expired);
	    } while(tm != UnetSys.TimerTail);
	}

	return(true);
}

/*******************************************************************************
********************************************************************************/
UINT8 reset_timer(TIMER *target_tm)
{
	TIMER *tm;

	if((tm = UnetSys.TimerTail) != NULL) {
	    do {
		if((tm = tm->Next) == target_tm) {
			set_expire_time(tm);
			return(true);
		}
	    } while(tm != UnetSys.TimerTail);
	}

	return(false);
}

/*******************************************************************************
********************************************************************************/
void close_timer(TIMER *tm)
{
	delete_node((void *)&UnetSys.TimerTail, (void *)&tm);
}

/*******************************************************************************
********************************************************************************/

#if defined(IOXC800)
void update_timer_chain(void)
#else
void update_timer_chain(void) REENTRANT
#endif
{
	TIMER *tm;

	timer_1ms_flag = 0;

	if((tm = UnetSys.TimerTail) != NULL) {
	    do {
		tm = tm->Next;

		if(tm->expired)
			continue;

		if(tm->overflow) {			// timer counter will overflow
			if(tm->expire_time < tick_count) // count before overflow
				continue;
			tm->overflow = 0;
		}

		if(tm->expire_time > tick_count)	// count for normal condition
			continue;

		tm->expired = 1;

		if(tm->fn && !tm->timer_fn_busy) {
			tm->timer_fn_busy = 1;
			(*(tm->fn))(tm->fn_param);
			tm->timer_fn_busy = 0;
		}

		if(tm->close_timer_flag)
			close_timer(tm);
	    } while(UnetSys.TimerTail && (tm != UnetSys.TimerTail));
	}
}

/*******************************************************************************
********************************************************************************/
void WaitMS(UINT16 count)
{
	TIMER *tm;

	TRACE_printf(("WaitMS(%u)", count));

	tm = setup_timer(count, true, NULL, NULL);
	while(!is_timer_expired(tm));
}

/*******************************************************************************
********************************************************************************/
void InitTimerVars(void)
{
	tick_count = 0;
	timer_1ms_flag = 0;

#if SEND_MSG_TIME_STAMP
	MsgLineCnt = 0;
#endif // #if SEND_MSG_TIME_STAMP
}

/*******************************************************************************
********************************************************************************/
#pragma message (__LOC__ "UpdateTimerVars() is called by interrupt service routine.")
#if defined(__C51__)
#pragma NOAREGS
#endif
void UpdateTimerVars(void)
{
//	UBEC_Activate_SEN();

	++tick_count;		/* 1 millisecond system timer tick counter */
	timer_1ms_flag = 1;

#if 0
	if((tick_count & 0x3FF) == 0) {	// one second
		NOP();			// DEBUG only: break point for stack overflow hunting
	}
#endif

#if SEND_MSG_TIME_STAMP
	MsgLineCnt = 0;
#endif // #if SEND_MSG_TIME_STAMP

//	UBEC_Deactivate_SEN();
}
